// internal/service/security_service.go
package service

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"

	"github.com/jfastfiler/internal/dao"
	"github.com/jfastfiler/internal/model"
	"github.com/jfastfiler/pkg/security"
)

type SecurityService struct {
	fileDAO       *dao.FileMetadataDAO
	auditDAO      *dao.AuditDAO
	virusScanner  *security.VirusScanner
	watermark     *security.Watermark
	encryptionKey []byte
}

func NewSecurityService(fileDAO *dao.FileMetadataDAO, auditDAO *dao.AuditDAO, 
	virusScanner *security.VirusScanner, watermark *security.Watermark, encryptionKey string) *SecurityService {
	
	return &SecurityService{
		fileDAO:       fileDAO,
		auditDAO:      auditDAO,
		virusScanner:  virusScanner,
		watermark:     watermark,
		encryptionKey:  []byte(encryptionKey),
	}
}

type ScanResult struct {
	Infected bool     `json:"infected"`
	Threats  []string `json:"threats,omitempty"`
	Scanned  bool     `json:"scanned"`
	Error    string   `json:"error,omitempty"`
}

type WatermarkRequest struct {
	FileID   int    `json:"file_id"`
	Text     string `json:"text,omitempty"`
	Opacity  float64 `json:"opacity,omitempty"`
	FontSize int    `json:"font_size,omitempty"`
	Position string `json:"position,omitempty"` // center, top-left, top-right, bottom-left, bottom-right
}

func (s *SecurityService) ScanFile(filePath string) (*ScanResult, error) {
	if s.virusScanner == nil || !s.virusScanner.Enabled {
		return &ScanResult{
			Scanned: false,
			Error:   "病毒扫描未启用",
		}, nil
	}

	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	infected, threats, err := s.virusScanner.ScanFile(filePath)
	if err != nil {
		return &ScanResult{
			Scanned: true,
			Error:   err.Error(),
		}, nil
	}

	return &ScanResult{
		Infected: infected,
		Threats:  threats,
		Scanned:  true,
	}, nil
}

func (s *SecurityService) ScanFileByID(fileID int) (*ScanResult, error) {
	file, err := s.fileDAO.GetByID(fileID)
	if err != nil {
		return nil, errors.New("文件不存在")
	}

	filePath := filepath.Join(s.storageDir, file.Path)
	return s.ScanFile(filePath)
}

func (s *SecurityService) AddWatermark(req *WatermarkRequest, user *model.User) (string, error) {
	if s.watermark == nil || !s.watermark.Enabled {
		return "", errors.New("水印功能未启用")
	}

	file, err := s.fileDAO.GetByID(req.FileID)
	if err != nil {
		return "", errors.New("文件不存在")
	}

	// 检查文件类型是否支持水印
	if !s.isWatermarkable(file) {
		return "", errors.New("该文件类型不支持添加水印")
	}

	filePath := filepath.Join(s.storageDir, file.Path)
	
	// 生成水印文本
	watermarkText := req.Text
	if watermarkText == "" {
		watermarkText = s.watermark.GenerateWatermarkText(user.Username)
	}

	// 创建水印文件路径
	watermarkedPath := filepath.Join(s.tempDir, fmt.Sprintf("watermarked_%d%s", file.ID, filepath.Ext(file.Path)))

	// 添加水印
	err = s.watermark.AddWatermarkToImage(filePath, watermarkedPath, watermarkText, req.Opacity, req.FontSize, req.Position)
	if err != nil {
		return "", fmt.Errorf("添加水印失败: %v", err)
	}

	return watermarkedPath, nil
}

func (s *SecurityService) isWatermarkable(file *model.FileMetadata) bool {
	watermarkableExts := map[string]bool{
		".jpg": true, ".jpeg": true, ".png": true, 
		".bmp": true, ".tiff": true, ".tif": true,
	}
	return watermarkableExts[strings.ToLower(file.FileExt)]
}

func (s *SecurityService) EncryptFile(filePath string) ([]byte, error) {
	// 读取文件内容
	plaintext, err := os.ReadFile(filePath)
	if err != nil {
		return nil, err
	}

	// 创建AES加密器
	block, err := aes.NewCipher(s.encryptionKey)
	if err != nil {
		return nil, err
	}

	// 创建GCM模式
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	// 生成随机nonce
	nonce := make([]byte, gcm.NonceSize())
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		return nil, err
	}

	// 加密数据
	ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)

	return ciphertext, nil
}

func (s *SecurityService) DecryptFile(encryptedData []byte) ([]byte, error) {
	// 创建AES加密器
	block, err := aes.NewCipher(s.encryptionKey)
	if err != nil {
		return nil, err
	}

	// 创建GCM模式
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	// 提取nonce
	nonceSize := gcm.NonceSize()
	if len(encryptedData) < nonceSize {
		return nil, errors.New("加密数据太短")
	}

	nonce, ciphertext := encryptedData[:nonceSize], encryptedData[nonceSize:]

	// 解密数据
	plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
	if err != nil {
		return nil, err
	}

	return plaintext, nil
}

func (s *SecurityService) LogSecurityEvent(userID int, action, path, details string) {
	s.auditDAO.Create(&model.AuditLog{
		UserID:  userID,
		Action:  "security_" + action,
		Path:    path,
		Details: details,
		Status:  "security",
	})
}